#ifndef SM2_EC_H
#define SM2_EC_H

#include "sm2_operation.h"
#include "sm2_safegcd.h"

#define PRE_G_WINDOW_7
// Defination of PCs
#define SM2_POINT_INFINTE 0x0
#define SM2_POINT_COMPRESSED 0x2
#define SM2_POINT_UNCOMPRESSED 0x4
#define SM2_POINT_MIXED 0x6

/* Point Type */
typedef struct {
    sm2_uint256_t x;
    sm2_uint256_t y;
    sm2_uint256_t z;
} SM2_Jacobian_Point;

typedef struct {
    sm2_uint256_t x;
    sm2_uint256_t y;
} SM2_Point;

typedef struct {
    sm2_uint256_t p;
    sm2_uint256_t a; 
    sm2_uint256_t b; 
    sm2_uint256_t n;
    sm2_uint256_t x_g; 
    sm2_uint256_t y_g;
} EC;

extern const SM2_Jacobian_Point SM2_G;
void print_std_point(const SM2_Point *p);
void sm2_set_jacobian_point(SM2_Jacobian_Point *result, const sm2_uint256_t x, const sm2_uint256_t y);
void sm2_set_jacobian_point_from_std(SM2_Jacobian_Point *result, const SM2_Point *a);
void sm2_get_std_point(SM2_Point *result, const SM2_Jacobian_Point *p);
void sm2_get_affine_point(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p);
void sm2_jacobian_point_k_mul(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *a, const sm2_uint256_t k);

void sm2_point_mul_generator(SM2_Jacobian_Point *R, const uint64_t* k);

void sm2_set_point_infi(SM2_Jacobian_Point *p);
void sm2_point_copy(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p);
int sm2_is_point_inverse(const SM2_Jacobian_Point *p1, const SM2_Jacobian_Point *p2);
int sm2_jacobian_point_equal(const SM2_Jacobian_Point *p1, const SM2_Jacobian_Point *p2);
void sm2_jacobian_point_add(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p1, const SM2_Jacobian_Point *p2);
void print_point(const SM2_Jacobian_Point *p);
void sm2_point_double(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p);
void sm2_jacobian_point_neg(SM2_Jacobian_Point *result, const SM2_Jacobian_Point *p);
#endif

